package no.cicero.testframework.execution;

import no.cicero.testframework.config.Config;
import no.cicero.testframework.model.testcase.TestCase;
import no.cicero.testframework.model.usecase.UseCase;
import no.cicero.testframework.reporting.Reporting;
import no.cicero.testframework.reporting.ReportingTestCase;
import no.cicero.testframework.reporting.ReportingUseCase;
import no.cicero.testframework.reporting.reports.HtmlConsolidatedReport;
import no.cicero.testframework.reporting.reports.HtmlDetailedReport;
import no.cicero.testframework.reporting.reports.ProgressReport;
import no.cicero.testframework.reporting.reports.TimeReport;
import no.cicero.testframework.xml.testcase.TestCaseImporter;
import no.cicero.testframework.xml.usecase.UseCaseImporter;
import org.apache.commons.io.FileUtils;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UseCasesRunner implements Runnable{
	public static final String OUTPUT_DEFAULT_FOLDER = "report";

	private final Config config;
	private final SAXParser parser;
	private final Reporting reporting;

	public UseCasesRunner(Config cfg, int userNo) throws ParserConfigurationException, SAXException, IOException {
		config = cfg;
		parser = SAXParserFactory.newInstance().newSAXParser();
		reporting = new Reporting();

		String folderName = OUTPUT_DEFAULT_FOLDER;
		if(cfg.getNumberOfUsers() > 1)
			folderName += userNo;

		File outputDir = new File(config.getOutputLocation(), folderName);
        if ( outputDir.exists() )
            FileUtils.deleteDirectory(outputDir);
        FileUtils.forceMkdir(outputDir);

		File timeDir = new File(config.getOutputLocation(), OUTPUT_DEFAULT_FOLDER);
        FileUtils.forceMkdir(timeDir);

		reporting.addReport(new ProgressReport());
		reporting.addReport(new HtmlDetailedReport(outputDir, config.getTemplateLocation()));
		reporting.addReport(new HtmlConsolidatedReport(outputDir, config.getTemplateLocation()));
		reporting.addReport(new TimeReport(timeDir));
	}

	public void run() {
		try{
			reporting.reportStarted();
			try {
				runUseCases();
			} finally {
				reporting.reportFinished();
			}
		} catch (Exception ex) {
			Logger.getLogger(UseCasesRunner.class.getName()).log(Level.SEVERE, null, ex);
			//throw new RuntimeException(ex);
		}
	}

	private void runUseCases() throws IOException, SAXException {
		for (String useCaseFile : config.getUseCaseNames()) {
			try {
				executeUseCase(useCaseFile);
				reporting.useCaseSucceed();
			} catch (Exception ex) {
				reporting.useCaseFailed(ex);
			}
		}
	}

	private void executeUseCase(String useCaseFile) throws IOException, SAXException {
		UseCase useCase = new UseCaseImporter(parser).doImport(new File(config.getUseCaseLocation(), useCaseFile));
		ReportingUseCase useCaseReport = reporting.useCaseStart(useCaseFile, useCase.getDescription(), useCase.getShortDescription());

		for (String testCaseName : useCase.getTestCases()) {
			if(!config.matchesTestCase(testCaseName))
				continue;
            TestCase testCase = loadTestCase(testCaseName, useCase);
			try {
				executeTestCase(testCaseName, testCase, useCaseReport);
				useCaseReport.testCaseSucceed();
			} catch (Exception ex) {
				useCaseReport.testCaseFailed(ex);
			}
		}
	}

	private TestCase loadTestCase(String testCaseName, UseCase useCase) throws IOException, SAXException {
		TestCase testCase = new TestCaseImporter(parser).doImport(
			new File(new File(config.getTestCaseLocation(), useCase.getTestCaseLocation()), testCaseName)
		);

        return testCase;
    }

	private void executeTestCase(String testCaseName, TestCase testCase, ReportingUseCase useCaseReport) throws Exception {
		ReportingTestCase testCaseReport = useCaseReport.testCaseStart(testCaseName, testCase.getDescription());

		TestCaseRunner runner = new TestCaseRunner(testCase, config, testCaseReport);
		runner.run();
	}

}
